package br.com.marcio.bvh;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.media.opengl.*;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;

import com.jogamp.opengl.util.*;

import org.apollo.bvh.BVHFile;
import org.apollo.bvh.Joint;
import org.apollo.bvh.parser.BVHParser;
import org.apollo.bvh.parser.ParseException;

public class Main extends JFrame implements GLEventListener, ActionListener, KeyListener, MouseListener, MouseWheelListener {
	private static final long serialVersionUID = 1L;
	static Frame frame;

    GL2 gl;
    GLU glu;
    float camX = 20.0f;
    float camY = 20.0f;
    float camZ = -20.0f;
    float centerX = 0f;
    float centerY = 0f;
    float centerZ = 0f;
    BVHFile root = null;
    int i = 0, j = 0;
    float grau = 0.0f;
    boolean exibeMalha = true;
    float rotateCameraX = 0.0f;
    //int s = 0;
    
    public Main() {
    	frame.addKeyListener(this);
    	frame.addMouseWheelListener(this);
    	frame.addMouseListener(this);
    }
    
    public void camera(){
        // Especifica sistema de coordenadas de projeção
        gl.glMatrixMode(GL2.GL_PROJECTION);
        // Inicializa sistema de coordenadas de projeção
        gl.glLoadIdentity();
        // Especifica a projeção perspectiva(angulo,aspecto,zMin,zMax)
        glu.gluPerspective(45, 2048/1280, 0.2, 1500);

        glu.gluLookAt(camX, camY, camZ, centerX, centerY, centerZ, 0.0f, 1.0f, 0.0f);

        // Especifica sistema de coordenadas do modelo
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        // Inicializa sistema de coordenadas do modelo
        gl.glLoadIdentity();
    }
    public static void main(String[] args) {
        GLProfile glp = GLProfile.getDefault();
        GLCapabilities caps = new GLCapabilities(glp);
        GLCanvas canvas = new GLCanvas(caps);

        frame = new Frame("AWT Window Test");
        frame.setSize(300, 300);
        frame.add(canvas);
        frame.setVisible(true);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        canvas.addGLEventListener(new Main());
        
        Animator animator = new Animator(canvas);
        animator.start();
    }
    @Override
    public void display(GLAutoDrawable drawable) {
        update();
        render(drawable);
    }
    @Override
    public void dispose(GLAutoDrawable drawable) {
    }
    @Override
    public void init(GLAutoDrawable drawable) {
    	gl = drawable.getGL().getGL2();
		glu = new GLU();
		camera();
		
		try {
			//root = BVHParser.parseFile(new File("bvh/Example1.bvh"));
			//root = BVHParser.parseFile(new File("bvh/exemplo.bvh"));
			root = BVHParser.parseFile(new File("bvh/dance.bvh"));
			root.getRoot().setZ(1.0f);
			//root = BVHParser.parseFile(new File("bvh/dance_legs.bvh"));
			//root = BVHParser.parseFile(new File("bvh/teste.bvh"));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    @Override
    public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
    	System.out.println("reshape");
    }
    
    private void update() {
    	//System.out.println("update");
    	//for(int i=0; i<=5; i++)
    	//System.out.println(root.getRoot().getChannels().get(i).getName());
    }
    
    private void render(GLAutoDrawable drawable) {
        GL2 gl = drawable.getGL().getGL2();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);


        if(exibeMalha)
        	malha();
        camera();
        
        gl.glPushMatrix();
	    //    grau+=20.0f;
	        gl.glRotatef(grau, 0.0f, 1.0f, 0.0f);
			gl.glBegin(GL.GL_LINES);
	        exibeEsqueleto(root.getRoot());
			gl.glEnd();
		gl.glPopMatrix();
//		try {
//			Thread.sleep(200);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
        
//		atualizaEsqueleto();
//		try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
    }

    int a = 0;
    int b = 0;
    public void atualizaEsqueleto(){
    	br.com.pontov.math.Vector3D v = new br.com.pontov.math.Vector3D();
    	if(root!=null){
    		v.setX(root.getRoot().getX());
    		//System.out.println(v.getX()+":"+root.getRoot().getX());
    		v.setY(root.getRoot().getY());
    		//System.out.println(v.getY()+":"+root.getRoot().getY());
    		v.setZ(root.getRoot().getZ());
    		//System.out.println(v.getZ()+":"+root.getRoot().getZ());
    		
    		b = 0;
    		v = v.rotateMeZ(root.getMotion().getData()[a][b]);
    		b = 1;
    		v = v.rotateMeX(root.getMotion().getData()[a][b]);
    		b = 2;
    		v = v.rotateMeY(root.getMotion().getData()[a][b]);
    		a = (a==218)?0:a++;
    		root.getRoot().setX(Float.parseFloat(""+v.getX()));
    		root.getRoot().setY(Float.parseFloat(""+v.getY()));
    		root.getRoot().setZ(Float.parseFloat(""+v.getZ()));
    	}// else {
    	//	root.getRoot().setX(1.0f);
    	//	for(int i=0; i<root.getChildren().size(); i++)
		//		exibeEsqueleto(root.getChildren().get(i));
    	//}
    }
    
    public void exibeEsqueleto(Joint root){
    	if(root!=null && root.getParent()!=null){
    		float posicao[] = posicaoRelativa(root);
    		float posicaoPai[] = posicaoRelativa(root.getParent());;
    		
    				gl.glColor3f(1,1,1);
    				gl.glVertex3f(posicao[0],posicao[1],posicao[2]);
    				gl.glVertex3f(posicaoPai[0],posicaoPai[1],posicaoPai[2]);
    			
    			if(root.getChildren()!=null)
    				for(int i=0; i<root.getChildren().size(); i++)
    					exibeEsqueleto(root.getChildren().get(i));
    		} else {
    			for(int i=0; i<root.getChildren().size(); i++)
					exibeEsqueleto(root.getChildren().get(i));
    		}
    	}
    public float[] posicaoRelativa(Joint joint) {
    	float x = joint.getX();
    	float y = joint.getY();
    	float z = joint.getZ();
    	
    	if(x==0.0f && y==0.0f && z==0.0f)
    		return new float[]{x, y, z};
    	else while (joint !=null) {
    		joint = joint.getParent();
    		if(joint!=null){
	    		x += joint.getX();
	        	y += joint.getY();
	        	z += joint.getZ();
    		}
    	}
    	return new float[]{x, y, z};
    }
    public void malha(){
        //Linha em Verde em cima do eixo X
        gl.glColor3f(0.0f, 1.0f, 0.0f);
        gl.glBegin(GL.GL_LINES);
	        gl.glVertex3f(-8.0f, 0.0f, 0.0f);
	        gl.glVertex3f(8.0f, 0.0f, 0.0f);
        gl.glEnd();
        //LGLCanvasinhas brancas paralelas
        gl.glColor3f(0.2f,0.2f,0.2f);
        gl.glBegin(GL.GL_LINES);
        	for(int i=0; i<=16; i++) {
        		if(i==8)
        			continue;
		        gl.glVertex3f(-8.0f, 0.0f, (float)(i-8));
		        gl.glVertex3f( 8.0f, 0.0f, (float)(i-8));
        	}
        gl.glEnd();
        
        
        //Linha Vermelha em cima do eixo Z
        gl.glColor3f(1.0f, 0.0f, 0.0f);
        gl.glBegin(GL.GL_LINES);
	        gl.glVertex3f(0.0f, 0.0f, -8.0f);
	        gl.glVertex3f(0.0f, 0.0f, 8.0f);
        gl.glEnd();
        //Linhas brancas paralelas
        gl.glColor3f(0.2f, 0.2f, 0.2f);
        gl.glBegin(GL.GL_LINES);
        	for(int i=0; i<=16; i++) {
        		if(i==8)
        			continue;
		        gl.glVertex3f((float)(i-8), 0.0f, -8.0f);
		        gl.glVertex3f((float)(i-8), 0.0f, 8.0f);
        	}
        gl.glEnd();
    }
//----------------------------------------------------KeyListener----------------------------------------------------
	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode())
        {
        	case KeyEvent.VK_RIGHT:
        	case KeyEvent.VK_NUMPAD6:
        		System.out.println("Direita");
        		centerX--;
            break;
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_NUMPAD4:
            	System.out.println("Esquerda");
            	centerX++;
                break;
            case KeyEvent.VK_UP:
            case KeyEvent.VK_NUMPAD8:
            	System.out.println("Cima");
            	centerY++;
            	break;
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_NUMPAD2:
            	System.out.println("Baixo");
            	centerY--;
            	break;
            case 61:
            case 107: // + do NumPad
            	System.out.println("Aproxima");
            	camX=(camX>1)?camX-1.0f:camX;
            	camY=(camY>1)?camY-1.0f:camY;
            	camZ=(camZ<-1)?camZ+1.0f:camZ;
            	System.out.println("X="+camX+" Y="+camY+" Z="+camZ);
            	break;
            case 45:
            case 109: // - do NumPad
            	System.out.println("Afasta");
            	camX=(camX<100)?camX+1.0f:camX;
            	camY=(camY<100)?camY+1.0f:camY;
            	camZ=(camZ>-100)?camZ-1.0f:camZ;
            	System.out.println("X="+camX+" Y="+camY+" Z="+camZ);
            	break;
            case KeyEvent.VK_M:
            	exibeMalha=(exibeMalha)?false:true;
            	
            case KeyEvent.VK_A:
            	grau-=20;
            	break;
            case KeyEvent.VK_D:
            	grau+=20;
            	break;
            case KeyEvent.VK_U: //update
            	System.out.println("Tecla u: update");
            	//s=(s==0)?1:0;
            	atualizaEsqueleto();
            	break;
            default:
            	System.out.println(e.getKeyCode());
        }
	}
	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
	}

//----------------------------------------------------mouseWheelListner----------------------------------------------------
	@Override
	public void mouseWheelMoved(MouseWheelEvent e) {
		switch (e.getWheelRotation())
        {
		case -1:
			System.out.println("Aproxima");
        	camX=(camX>1)?camX-1.0f:camX;
        	camY=(camY>1)?camY-1.0f:camY;
        	camZ=(camZ<-1)?camZ+1.0f:camZ;
        	System.out.println("X="+camX+" Y="+camY+" Z="+camZ);
			break;
		case 1:
			System.out.println("Afasta");
        	camX=(camX<100)?camX+1.0f:camX;
        	camY=(camY<100)?camY+1.0f:camY;
        	camZ=(camZ>-100)?camZ-1.0f:camZ;
        	System.out.println("X="+camX+" Y="+camY+" Z="+camZ);
        	break;
		default:
			System.out.println(e.getWheelRotation());
        }
	}
//----------------------------------------------------mouseListner----------------------------------------------------
	@Override
	public void mouseClicked(MouseEvent e) {
		System.out.println(e.getButton());
		switch (e.getModifiers())
        {
		default:
			System.out.println(e.getModifiers());
        }
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		System.out.println("mouseEntered()");
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

}